package com.google.code.xconf;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.List;

public class ConfigurationWriter {

    private String configurationToString(Configuration configuration) {
        StringBuilder sb = new StringBuilder();
        for (Property node : configuration.getNodes()) {
            sb.append(toString(node)).append("\n");
        }
        return sb.toString();
    }

    private String propertyGroupToString(PropertyGroup propertyGroup, int level) {
        StringBuilder sb = new StringBuilder();
        String indent = "";
        for (int i = 0 ; i < level; i ++) {
            indent += "\t";
        }
        sb.append("<").append(normalizeToken(propertyGroup.getName()));
        sb.append(valuesToString(propertyGroup.getValues()));
        sb.append(">\n");
        sb.append(nodesToString(propertyGroup.getNodes(), ++level));
        sb.append(indent);
        sb.append("</").append(normalizeToken(propertyGroup.getName())).append(">");
        return sb.toString();
    }

    private String valuesToString(List<String> args) {
        StringBuilder sb = new StringBuilder();
        for (String arg : args) {
            sb.append(" ").append(normalizeToken(arg));
        }
        return sb.toString();
    }

    private String nodesToString(Collection<Property> nodes, int level) {
        StringBuilder sb = new StringBuilder();
        String indent = "";
        for (int i = 0 ; i < level; i ++) {
            indent += "\t";
        }
        for (Property node : nodes) {
            sb.append(indent);
            if (node instanceof PropertyGroup) {
                sb.append(propertyGroupToString((PropertyGroup) node, level));
            } else {
                sb.append(propertyToString(node));
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    public String propertyToString(Property property) {
        return normalizeToken(property.getName()) + valuesToString(property.getValues());
    }

    public String normalizeToken(String token) {
        if (token.contains(" ") || token.contains("#") || token.contains("\t")) {
            return "\"" + token + "\"";
        }
        return token;
    }

    public String toString(Property property) {
        if (property instanceof Configuration) {
            return configurationToString((Configuration) property);
        }
        if (property instanceof PropertyGroup) {
            return propertyGroupToString((PropertyGroup) property, 0);
        }
        return propertyToString(property);
    }

    public void writeTo(Property property, OutputStream outputStream) throws IOException {
        writeTo(property, outputStream, Charset.forName("UTF-8"));
    }

    public void writeTo(Property property, OutputStream outputStream, Charset charset) throws IOException {
        outputStream.write(toString(property).getBytes(charset));
    }

}
